/*
 libevent在socket异步编程的一个简单的实例，主要是让刚开始学习libevent的有个直观的印象
*/

#include <stdio.h>   
//#include <string.h>   
//#include <iostream>   
#include <sys/socket.h>       
#include <netinet/in.h>       
#include <arpa/inet.h>       
#include <netdb.h> 
   
#include <event.h>   
 
const int SERVICE_PORT = 6666;
const int SERVICE_BACKLOG = 5;
const int BUFFER_SIZE = 1024；
 
 
//using namespace std;       
// 事件base   
struct event_base* base; 
 
struct sock_ev {
    struct event* request_ev;
    struct event* reply_ev;
    char* recBuffer;
    char* sendBuffer;
};  
    
void release_sock_event(struct sock_ev* ev)
{
    event_del(ev->request_ev);
    free(ev->request_ev);
    free(ev->reply_ev);
    free(ev->recBuffer);
    free(ev->sendBuffer);
    free(ev);
}
 
// 响应事件回调函数   
void on_reply(int sock, short event, void* arg)
{
    char* buffer = (char*)arg;
    send(sock, buffer, strlen(buffer), 0);
 
    free(buffer);
}
    
// 接收事件回调函数   
void on_request(int sock, short iEvent, void *arg)   
{   
    int iLen;
    struct sock_ev* ev = (struct sock_ev*)arg;
    ev->recBuffer = (char*)malloc(BUFFER_SIZE);
    bzero(ev->recBuffer, BUFFER_SIZE);
    ev->sendBuffer = (char*)malloc(BUFFER_SIZE);
    bzero(ev->sendBuffer, BUFFER_SIZE);
    iLen = recv(sock, ev->recBuffer, BUFFER_SIZE, 0);
     
    printf("receive data:%s, size:%d\n", ev->recBuffer, iLen);
    // 连接结束(=0)或连接错误(<0)，将事件删除并释放内存空间   
    if (iLen <= 0) {
        release_sock_event(ev);
        close(sock);
        return;
    }
 
    /*
    do something about request--such as decode,handel the session
    */
     
    //after handel the request,reply to the client
    event_set(ev->reply_ev, sock, EV_WRITE, on_reply, ev->sendBuffer);
    event_base_set(base, ev->reply_ev);
    event_add(ev->reply_ev, NULL);
}   
     
// 连接请求事件回调函数   
void on_Accept(int iSvrFd, short iEvent, void *arg)   
{   
    int iNewFd;   
    struct sockaddr_in sCliAddr;   
     
    socklen_t iSinSize = sizeof(sCliAddr);   
    iNewFd = accept(iSvrFd, (struct sockaddr*)&sCliAddr, &iSinSize);   
     
    // 连接注册为新事件 (EV_PERSIST为事件触发后不默认删除) 
    struct sock_ev* ev = (struct sock_ev*)malloc(sizeof(struct sock_ev));
    ev->request_ev = (struct event*)malloc(sizeof(struct event));
    ev->reply_ev = (struct event*)malloc(sizeof(struct event));
     
    event_set(ev->request_ev, iNewFd, EV_READ|EV_PERSIST, on_request, ev);
    event_base_set(base, ev->request_ev);
    event_add(ev->request_ev, NULL);
}   
     
int main(int argc, char* argv[])
{     
    /*
    初始化服务器--BEGIN
    */
    // 创建tcpSocket（iSvrFd）
    int iSvrFd;      
    iSvrFd = socket(AF_INET, SOCK_STREAM, 0); 
    int yes = 1；
    setsockopt(iSvrFd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
     
    //创建服务端
    struct sockaddr_in sSvrAddr;  
    memset(&sSvrAddr, 0, sizeof(sSvrAddr));     
    sSvrAddr.sin_family = AF_INET;     
    sSvrAddr.sin_addr.s_addr = INADDR_ANY;   
    sSvrAddr.sin_port = htons(SERVICE_PORT);      
                                 
    // 绑定端口并监听本机端口     
    bind(iSvrFd, (struct sockaddr*)&sSvrAddr, sizeof(sSvrAddr));     
    listen(iSvrFd, SERVICE_BACKLOG);   
    /*
    初始化服务器--END
    */
     
    // 初始化base   
    base = event_base_new();   
         
    struct event evListen;   
    // 设置事件   
    event_set(&evListen, iSvrFd, EV_READ|EV_PERSIST, on_Accept, NULL);   
    // 设置为base事件   
    event_base_set(base, &evListen);   
    // 添加事件   
    event_add(&evListen, NULL);   
         
    // 事件循环   
    event_base_dispatch(base);   
     
    return 0;   
}